package manager
{
	
	import br.com.stimuli.loading.BulkLoader;
	import br.com.stimuli.loading.BulkProgressEvent;
	import event.*;
	import flash.display.*;
	import flash.events.*;
	import flash.net.*;
	
	import log.Logger;
	
	/**
	 * -- ResourceMgr --
	 * @desc	resource manager, used to load and manage resources, such as xml, png and mp3 files
	 * @author	Aqua (built on 2011-11-09)
	 */
	public class ResourceMgr
	{
		//---------------------//
		//      Singleton      //
		//---------------------//
		
		/**************************************************************************
		 * -- (getter) instance --
		 * @desc		get singleton of this class
		 * @return		singleton of this class
		 *************************************************************************/
		public static function get instance():ResourceMgr
		{
			if (null == _instance)
			{
				_instance = new ResourceMgr(singleton);
			}
		
			return _instance;
		}
		
		/**************************************************************************
		 * -- singleton --
		 * @desc		a private function used to enforce singlton
		 *************************************************************************/
		private static function singleton():void
		{
			
		}
		
		
		//---------------------//
		//     Constructor     //
		//---------------------//
		
		/**************************************************************************
		 * -- ResourceMgr --
		 * @desc		constructor
		 * @param		(s) a private function used to enforce singlton
		 *************************************************************************/
		public function ResourceMgr(s:Function = null):void
		{
			if (singleton != s)
			{
				throw new Error("This is a singleton class!");
			}
			
			_cacheList = [];
			_imgPool = {
				"camp"		: {},
				"character"	: {},
				"weapon"	: {},
				"armor"		: {},
				"accessory"	: {},
				"skill"		: {}
			};
		}
		
		
		//-----------------//
		//     Publics     //
		//-----------------//
		
		/**************************************************************************
		 * -- (getter) percentLoaded --
		 * @desc		get how much percent of resources is loaded
		 * @return		percent of loaded resouces
		 *************************************************************************/
		public function get percentLoaded():Number
		{
			return _percentLoaded;
		}
		
		/**************************************************************************
		 * -- (getter) loadComplete --
		 * @desc		get if loading is completed
		 * return 		if loading is completed
		 **************************************************************************/
		public function get loadComplete():Boolean
		{
			return _loadComplete;
		}
		
		/**************************************************************************
		 * -- loadRes --
		 * @desc		start to load all resources
		 * @param		(resp) response function which will be called when all
		 *				resources are loaded
		 *************************************************************************/
		public function loadRes():void
		{
			if (_loadComplete)
			{
				return;
			}
			
			Logger.log("** start loading resources");
			
			_path = (GameMgr.instance.localMode ? GameMgr.instance.PATH_LOCAL : GameMgr.instance.PATH);
			
			_bulkLoader = new BulkLoader("main");
			_bulkLoader.addEventListener(BulkProgressEvent.PROGRESS, onProgress);
			_bulkLoader.addEventListener(BulkProgressEvent.COMPLETE, onComplete);
			
			addXML("settings");
			addXML("characters");
			addXML("camps");
			addXML("stages");
			
			_percentLoaded = 0;
			_loadComplete = false;
			_bulkLoader.start();
		}
		
		/**************************************************************************
		 * -- getRes --
		 * @desc		get resource
		 * @param		(name) name of resource
		 * @return		needed resource
		 *************************************************************************/
		public function getRes(name:String):*
		{
			var type:String;
			var file:*;
			
			type = name.substr(0, 3);
			
			switch(type)
			{
				case "xml":
					file = _bulkLoader.getXML(name);
					break;
				case "img":
					
					break;
				default:
					break;
			}
			
			return file;
		}
		
		/**************************************************************************
		 * -- loadImg --
		 * @desc		load an image file
		 * @param		(type) type of the image, like "character" or "weapon"
		 * @param		(name) file name of the image
		 * @param		(container) container used to contain image
		 *************************************************************************/
		public function loadImg(type:String, name:String, container:DisplayObjectContainer):void
		{
			var url:String;
			var loader:Loader;
			var obj:Object;
			var o:Object;
			var index:String;
			
			if (! _imgPool[type])
			{
				throw new Error("Wrong image type!");
			}
			
			// if already in cache list, just wait for loading
			for each(o in _cacheList)
			{
				if (o.type == type && o.name == name && o.container == container)
				{
					return;
				}
			}
			
			// if image has been loaded before, add it to container directly
			if (_imgPool[type][name])
			{
				addBmpToContainer(type, name, container);
				return;
			}
			
			url = _path + "image/" + type + "/" + name + ".png";
			
			loader = new Loader();
			loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onError);
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
			
			// create an object to save information of this loader
			obj = {};
			obj.loader = loader;
			obj.type = type;
			obj.name = name;
			obj.container = container;
			_cacheList.push(obj);
			
			loader.load(new URLRequest(url));
			
			function onError(e:IOErrorEvent):void
			{
				Logger.log(String(e));
				loaderHandler(e, false);
			}
			function onComplete(e:Event):void
			{
				loaderHandler(e, true);
			}
			function loaderHandler(e:Event, success:Boolean):void
			{
				var loaderInfo:LoaderInfo;
				var bmpData:BitmapData;
				var index:String;
				
				e.target.removeEventListener(IOErrorEvent.IO_ERROR, onError);
				e.target.removeEventListener(Event.COMPLETE, onComplete);
				
				loaderInfo = e.target as LoaderInfo;
				
				// get information from cache list
				for (index in _cacheList)
				{
					o = _cacheList[index];
					if (o.loader == loaderInfo.loader)
					{
						if (success)
						{
							bmpData = new BitmapData(loaderInfo.width, loaderInfo.height);
							bmpData.draw(loaderInfo.content);
							_imgPool[o.type][o.name] = bmpData;
							addBmpToContainer(o.type, o.name, o.container);
						}
						_cacheList.splice(index, 1);
						break;
					}
				}
			}
			function addBmpToContainer(type:String, name:String, container:DisplayObjectContainer):void
			{
				var bmp:Bitmap;
				var bmpData:BitmapData;
				
				bmpData = BitmapData(_imgPool[type][name]).clone();
				bmp = new Bitmap(bmpData);
				bmp.name = type + "/" + name;
				container.addChild(bmp);
			}
		}
		
		
		//------------------//
		//     Privates     //
		//------------------//
		
		/**************************************************************************
		 * -- onProgress --
		 * @desc		loading processing event handler
		 * @param		(e) event information
		 *************************************************************************/
		private function onProgress(e:BulkProgressEvent):void
		{
			_percentLoaded = e.percentLoaded;
			Logger.log("Loading: " + String(_percentLoaded));
		}
		
		/**************************************************************************
		 * -- onComplete --
		 * @desc		loading completed event handler
		 * @param		(e) event information
		 *************************************************************************/
		private function onComplete(e:BulkProgressEvent):void
		{
			Logger.log("** resources loaded");
			
			_loadComplete = true;
			_bulkLoader.removeEventListener(BulkProgressEvent.PROGRESS, onProgress);
			_bulkLoader.removeEventListener(BulkProgressEvent.COMPLETE, onComplete);
		}
		
		/**************************************************************************
		 * -- addXML --
		 * @desc		add xml file to BulkLoader
		 * @param		(fileName) name of the file
		 *************************************************************************/
		private function addXML(fileName:String):void
		{
			var path:String;
			var props:Object;
			
			path = _path + "xml/" + fileName + ".xml";
			props = { "id":"xml_" + fileName };
			
			_bulkLoader.add(path, props);
		}
		
		/**************************************************************************
		 * -- addImage --
		 * @desc		add image file to BulkLoader
		 * @param		(fileName) name of the file
		 *************************************************************************/
		private function addImage(fileName:String):void
		{
			var path:String;
			var props:Object;
			
			path = _path + "image/" + fileName + ".png";
			props = { "id":"img_" + fileName };
			
			_bulkLoader.add(path, props);
		}
		
		
		private static var _instance:ResourceMgr;
		
		public const CAMP	:String = "camp";
		public const CHARA	:String = "character";
		public const WEAPON	:String = "weapon";
		public const ARMOR	:String = "armor";
		public const ACC	:String = "accessory";
		public const SKILL	:String = "skill";
		
		private var _bulkLoader		:BulkLoader;
		private var _loadComplete	:Boolean;
		private var _percentLoaded	:Number;
		private var _path			:String;
		private var _imgPool		:Object;
		private var _cacheList		:Array;
	}
	
}